/*
尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理.
*/
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class MyPromise{ // 定一个类
    constructor(fn) {
        try{
            fn(this.resolve,this.reject) //执行执行器，因为有resolve和reject参数，所以定义这两个方法
        }catch (e){
            this.reject(e) // 执行器报错时处理
        }

    }
    status = PENDING;//状态

    value = undefined;//成功的值

    reason = undefined;// 失败的原因

    // successCallBackVal = undefined; // 储存成功回调的变量
    //
    // failCallBackVal = undefined; // 储存失败回调的变量

    successCallBackArr = []; // 储存成功回调的变量的数组

    failCallBackArr = []; // 储存失败回调的变量的数组
    resolve = (value)=>{ // resolve参数的方法
        if(this.status !== PENDING) return; //状态智能改变一次
        this.status = FULFILLED; //成功状态
        this.value = value; //成功的值赋值
        // this.successCallBackVal && this.successCallBackVal(this.value) //如果successCallBackVal有值则执行
        while (this.successCallBackArr.length){ //当多次调用then，且执行器中还有异步方法时，shift拿到第一个，直接执行
            this.successCallBackArr.shift()() // 等待时已经赋值了，所以这里不用赋值了
        }
    }
    reject = (reason)=>{ // reject参数的方法
        if(this.status !== PENDING) return; //状态智能改变一次
        this.status = REJECTED; //失败状态
        this.reason = reason; //失败的理由赋值
        // this.failCallBackVal && this.failCallBackVal(this.reason) //如果failCallBackVal有值则执行
        while (this.failCallBackArr.length){ //当多次调用then，且执行器中还有异步方法时，shift拿到第一个，直接执行
            this.failCallBackArr.shift()() // 等待时已经赋值了，所以这里不用赋值了
        }
    }
    then(successCallBack,failCallBack){ // 定义then方法
        successCallBack = successCallBack ? successCallBack : value => value; // successCallBack 不一定传的时候
        failCallBack = failCallBack ? failCallBack : reason => {throw reason}; // failCallBack 不一定传的时候
        let promise = new MyPromise((resolve,reject)=>{ // 链式调用时，then要返回一个promise对象
            if(this.status === FULFILLED){
                setTimeout(()=>{ // 延后执行，要不获取不到promise
                    try{
                        let x = successCallBack(this.value) //执行成功回调
                        resolvePromise(promise,x,resolve,reject) // 把成功得到的值，放在执行器其中，给到下一个then方法
                    }catch (e) {
                        console.log(e); // then方法出现错误时
                    }
                },0)
            }else if(this.status === REJECTED){
                setTimeout(()=>{
                    try{
                        let y = failCallBack(this.reason) //执行失败回调
                        rejectPromise(y,resolve,reject) // 把失败得到的值，放在执行器其中，给到下一个then方法
                    }catch (e) {
                        console.log(e);
                    }
                },0)
            }else{ //当执行器中有异步的时候，then执行时并没有改变状态
                // this.successCallBackVal = successCallBack;
                // this.failCallBackVal = failCallBack;

                //当多次then调用时且执行器还有异步代码，都要延后执行
                this.successCallBackArr.push(()=>{
                    setTimeout(()=>{ // 延后执行，要不获取不到promise
                        try{
                            let x = successCallBack(this.value) //执行成功回调
                            resolvePromise(promise,x,resolve,reject) // 把成功得到的值，放在执行器其中，给到下一个then方法
                        }catch (e) {
                            console.log(e); // then方法出现错误时
                        }
                    },0)
                })
                this.failCallBackArr.push(()=>{
                    setTimeout(()=>{
                        try{
                            let y = failCallBack(this.reason) //执行失败回调
                            rejectPromise(y,resolve,reject) // 把失败得到的值，放在执行器其中，给到下一个then方法
                        }catch (e) {
                            console.log(e);
                        }
                    },0)
                })
            }
        })
        return promise
    }
    static all(array){ // 静态方法
        let arr = [];
        let index = 0;
        return new MyPromise((resolve,reject)=>{
            function addData(i,val) {
                arr[i] = val;
                index++;
                if(array.length === index){
                    resolve(arr)
                }
            }
            for(let i=0;i<array.length;i++){
                if(array[i] instanceof MyPromise){ // 因为数组里面是对象或者值都可以
                    array[i].then((value)=>{
                        return addData(i,value)
                    },(reason)=>{
                        return reject(reason)
                    })
                }else{
                    addData(i,array[i])
                }
            }
        })
    }
    static resolve(value){
        if(value instanceof MyPromise) return value; // 是promise对象直接返回
        return new MyPromise(resolve=>resolve(value)); // 普通值变成对象返回
    }
    finally(callback){ // 对错都能执行，且返回promise对象，还要能执行callback回调函数
        return this.then((value)=>{
            return MyPromise.resolve(callback()).then(()=>value)
        },(reason)=>{
            return MyPromise.resolve(callback()).then(()=>{throw reason})
        })
    }
    catch(failCallBack){ // 只执行失败回调，所以成功回调处放undefined
        return this.then(undefined,failCallBack);
    }
}
// 链式调用then的时候，返回普通值和promise对象都可以
function resolvePromise(promise,x,resolve,reject) {
    if(promise === x){ //自己调自己时，要报错
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
    }
    if(x instanceof MyPromise){
        x.then((value)=>{
            resolve(value)
        },(reason)=>{
            reject(reason)
        })
    }else{
        resolve(x)
    }
}
function rejectPromise(y,resolve,reject) {
    if(y instanceof MyPromise){
        y.then((value)=>{
            resolve(value)
        },(reason)=>{
            reject(reason)
        })
    }else{
        reject(y)
    }
}